#coding:utf-8
'''
Created on 2015��4��18��

@author: guowu
'''
from PyQt4.QtGui import QWidget, QPixmap, QLinearGradient, QColor, QFont,\
    QPainter, QPen, QBrush, QTransform, QMainWindow, QPalette, QAction
from PyQt4.QtCore import QTimeLine, SIGNAL, QString, QPoint, QTime, QBasicTimer
from PyQt4.QtCore import Qt
from PyQt4.Qt import QApplication
import sys


class Digits(QWidget):
    def __init__(self,parent=None):
        super(Digits,self).__init__(parent)
        #Q_OBJECT

        #public:

        #/*Define three transition modes of the digital clock*/
        self.enum = ["Slide","Flip","Rotate"]
        
        #int m_number#number to set to digits
    
        #int m_transition#transition mode(change effect)
    
        #QPixmap m_pixmap#current time pixmap
        self.m_pixmap = QPixmap()
        #QPixmap m_lastPixmap#next state time pixmap
        self.m_lastPixmap = QPixmap()
        #QTimeLine m_animator
        self.m_animator = QTimeLine()
        #used to animate a GUI control by calling a slot periodically
        #The timeline's duration describes for how long the animation will run
        #connect the frameChanged() signal to a suitable slot in the widget you wish to animate
    
        #: QWidget(parent)
        #, m_number(0)
        #, m_transition(Slide)
        self.m_number = 0
        self.m_transition = 0
        
        
        self.setAttribute(Qt.WA_OpaquePaintEvent, True)
        #Widget paints all its pixels when it receives a paint event

        self.setAttribute(Qt.WA_NoSystemBackground, True)
        #Indicates that the widget has no background, i.e. when the widget receives paint events, the background is not automatically repainted.
        #self.m_animator.start()
        self.connect(self.m_animator, SIGNAL("frameChanged(int)"), self.update)
        #start animation

        self.m_animator.setFrameRange(0, 100)
        self.m_animator.setDuration(600)
        #Construct a 0.6-second timeline with a frame range of 0 - 100

        self.m_animator.setCurveShape(QTimeLine.EaseInOutCurve)
        #starts growing slowly, then runs steadily, then grows slowly again

    #Set transition when time changed*/
    def wwww(self):
        print "wwwwwwwwww"
    def setTransition(self, tr):
        self.m_transition = tr
    
    def getTransition(self):
        return self.m_transition
        
    def getBound(self,b , asecs, aMaxSeconds):
        if asecs < aMaxSeconds:
            a = asecs
        else:
            a = aMaxSeconds
            
        if b > a:
            return b
        else:
            return a
    #Get transition mode*/
    def transition(self): 
        return self.m_transition
    
    #Set hours and minutes*/
    def setNumber(self,n):
        print n
        if (self.m_number != n):
            self.m_number = self.getBound(0, n, 99)
            #self.preparePixmap()
            self.update()
    
    #Flip to next state*/
    def flipTo(self, n):
        print n
        if (self.m_number != n):
            self.m_number = self.getBound(0, n, 99)
            self.m_lastPixmap = self.m_pixmap
            self.update()
            self.m_animator.stop()
            self.m_animator.start()
    
    #Draw the main frame of the digits area*/
    def drawFrame(self,painter,rect):
        painter.setPen(Qt.NoPen)
        gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
        #Set linear gradient area
        gradient.setColorAt(0.00, QColor(245, 245, 245))
        gradient.setColorAt(0.49, QColor(192, 192, 192))
        gradient.setColorAt(0.51, QColor(245, 245, 245))
        gradient.setColorAt(1.00, QColor(192, 192, 192))
        #Creates stop points at the given position with the given color

        painter.setBrush(gradient)
        r = rect
        painter.drawRoundedRect(r, 15, 15, Qt.RelativeSize)
        '''
            Draws outer rectangle rect with rounded corners.
            Qt::RelativeSize specifies the size relative to the bounding rectangle,
            typically using percentage measurements.
        '''

        r.adjust(1, 4, -1, -4)
        #Adds 1, 4, -1 and -4 respectively to the existing coordinates of the rectangle

        painter.setPen(QColor(181, 181, 181))
        painter.setBrush(Qt.NoBrush)
        painter.drawRoundedRect(r, 15, 15, Qt.RelativeSize)
        #Draws inner rectangle rect with rounded corners.

        painter.setPen(QColor(159, 159, 159))
        y = rect.top() + rect.height() / 2 - 1
        painter.drawLine(rect.left(), y, rect.right(), y)
        #Draws the mid-line from (rect.left(), y) to (rect.right(), y) and sets the current pen position to (rect.right(), y)


    #Draw the digits*/
    def drawDigits(self, n, rect, p):
        scaleFactor = 2
        #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM)
        if (rect.height() > 240):
            scaleFactor = 1
            #endif

        str = QString.number(n)
        #print "111111111111111111",str
        if (str.length() == 1):
            str.prepend("0")
        #Ensure it is double-digit
        #print "111111111111111111",str
        font = QFont()
        font.setFamily("Helvetica")
        fontHeight = scaleFactor * 0.55 * rect.height()
        font.setPixelSize(fontHeight)
        #Sets the font size to pixelSize pixels

        font.setBold(True)

        pixmap = QPixmap(rect.size() * scaleFactor)
        pixmap.fill(Qt.transparent)

        gradient = QLinearGradient(QPoint(0, 0), QPoint(0, pixmap.height()))
        #Constructs a linear gradient with interpolation area between (0,0) and (0,pixmap.height())

        gradient.setColorAt(0.00, QColor(128, 128, 128))
        gradient.setColorAt(0.49, QColor(64, 64, 64))
        gradient.setColorAt(0.51, QColor(128, 128, 128))
        gradient.setColorAt(1.00, QColor(16, 16, 16))
        #Creates stop points at the given position with the given color

        #p = QPainter()
        #p.begin(pixmap)
        #p.begin(self)
        #p.drawPixmap(QRectF, QPixmap, QRectF)
        p.setFont(font)
        pen = QPen()
        pen.setBrush(QBrush(gradient))
        #Set penbrush with linergrident
        
        p.setPen(pen)
        print "111111111111111111",str
        p.drawText(pixmap.rect(), Qt.AlignCenter, str)
        #Draws the digit number(str here) within the provided rectangle
        #p.end()

        return pixmap.scaledToWidth(self.width(), Qt.SmoothTransformation);
        #Returns a scaled copy of the image which is transformed using bilinear filtering
    #prepare the pixmap  */
    def preparePixmap(self,p):
        #p.setBrush(Qt.NoBrush)
        #p.setPen(Qt.NoPen)
        m_pixmap = QPixmap(self.size())
        m_pixmap.fill(Qt.transparent)
        #Fills the pixmap with the given transparent black value (i.e., QColor(0, 0, 0, 0))

        #p = QPainter()
        #p.begin(self.m_pixmap)
        #p.begin(self)
        p.drawPixmap(0, 0, self.drawDigits(self.m_number, self.rect(),p))
        #Draws the given digits-pixmap at position (0, 0)

        #p.end()
    
    #define a resize event*/
    def resizeEvent(self,event):
        #self.preparePixmap()
        self.update()#Causes a paintEvent() call


    #Paint the static state*/
    def paintStatic(self,p):
        #p = QPainter(self)
        #return
        p.setBrush(Qt.NoBrush)
        p.setPen(Qt.NoPen)
        p.fillRect(self.rect(), Qt.black)
        #Fill the widget rec with black color

        pad = self.width() / 10
        self.drawFrame(p, self.rect().adjusted(pad, pad, -pad, -pad))
        p.drawPixmap(0, 0, self.m_pixmap)
    
    #Paint the slide state*/
    def paintSlide(self,p):
        #p = QPainter(self)
        p.setBrush(Qt.NoBrush)
        p.setPen(Qt.NoPen)
        #p.fillRect(self.rect(), Qt.black)

        pad = self.width() / 10
        fr = self.rect().adjusted(pad, pad, -pad, -pad);
        self.drawFrame(p, fr)
        p.setClipRect(fr)
        #sets the clip region to the given rectangle using the given clip operation

        y = self.height() * self.m_animator.currentFrame() / 100
        p.drawPixmap(0, y, self.m_lastPixmap)
        #Draw last-time state pixmap from 0 to height()(Y Coordinate)  in 0.6 second

        p.drawPixmap(0, y - self.height(), self.m_pixmap)
        #Draw current-time state pixmap from -height() to 0 (Y Coordinate) in 0.6 second
    
    #Paint the flip state*/
    def paintFlip(self,p):
        #return
        p.setBrush(Qt.NoBrush)
        p.setPen(Qt.NoPen)
        #p = QPainter(self)
        #if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_WINCE_WM)
        p.setRenderHint(QPainter.SmoothPixmapTransform, True)
        p.setRenderHint(QPainter.Antialiasing, True)
        #endif
        #p.fillRect(self.rect(), Qt.black)

        hw = self.width() / 2
        hh = self.height() / 2
        
        #behind is the new pixmap
        pad = self.width() / 10
        fr = self.rect().adjusted(pad, pad, -pad, -pad)
        self.drawFrame(p, fr)
        p.drawPixmap(0, 0, self.m_pixmap)

        index = self.m_animator.currentFrame()

        if (index <= 50):

            #the top part of the old pixmap is flipping
            angle = -180 * index / 100;
            transform = QTransform()
            transform.translate(hw, hh)
            #Moves the coordinate system to the center of widget

            transform.rotate(angle, Qt.XAxis)
            #Rotates the coordinate system counterclockwise by angle about the X axis

            p.setTransform(transform)
            self.drawFrame(p, fr.adjusted(-hw, -hh, -hw, -hh))
            p.drawPixmap(-hw, -hh, self.m_lastPixmap)

            #the bottom part is still the old pixmap
            p.resetTransform()
            p.setClipRect(0, hh, self.width(), hh)
            #Enables clipping, and sets the clip region to the rectangle beginning at (0, hh) with the given width and height

            self.drawFrame(p, fr)
            p.drawPixmap(0, 0, self.m_lastPixmap)
        else:

            p.setClipRect(0, hh, self.width(), hh)

            #the bottom part is still the old pixmap
            self.drawFrame(p, fr)
            p.drawPixmap(0, 0, self.m_lastPixmap)

            #the bottom part of the new pixmap is flipping
            angle = 180 - 180 * self.m_animator.currentFrame() / 100
            transform = QTransform()
            transform.translate(hw, hh)
            transform.rotate(angle, Qt.XAxis)
            p.setTransform(transform)
            self.drawFrame(p, fr.adjusted(-hw, -hh, -hw, -hh))
            p.drawPixmap(-hw, -hh, self.m_pixmap)
    
    #Paint the rotate state*/
    def paintRotate(self,p):
        #return
        #p = QPainter(self)
        p.setBrush(Qt.NoBrush)
        p.setPen(Qt.NoPen)

        pad = self.width() / 10
        fr = self.rect().adjusted(pad, pad, -pad, -pad)
        self.drawFrame(p, fr)
        p.setClipRect(fr)

        angle1 = -180 * self.m_animator.currentFrame() / 100
        angle2 = 180 - 180 * self.m_animator.currentFrame() / 100
        if self.m_animator.currentFrame() <= 50:
            angle = angle1
            pix = self.m_lastPixmap
        else:
            angle = angle2
            pix = self.m_pixmap
        #angle = (self.m_animator.currentFrame() <= 50) ? angle1 : angle2
        #QPixmap pix = (m_animator.currentFrame() <= 50) ? m_lastPixmap : m_pixmap;

        transform = QTransform()
        transform.translate(self.width() / 2, self.height() / 2)
        transform.rotate(angle, Qt.XAxis)

        p.setTransform(transform)
        p.setRenderHint(QPainter.SmoothPixmapTransform, True)
        p.drawPixmap(-self.width() / 2, -self.height() / 2, pix)
    
    def paintEvent(self,event):
        #Q_UNUSED(event);
        p = QPainter(self)
        #self.preparePixmap(p)
        #return
        print self.enum[self.transition()]
        if (self.m_animator.state() == QTimeLine.Running):
            #print "slide00000000000"
            if (self.enum[self.transition()] == "Slide"):
                #print "slide00000000000"
                self.paintSlide(p)
            if (self.enum[self.transition()] == "Flip"):
                self.paintFlip(p)
            if (self.enum[self.transition()] == "Rotate"):
                self.paintRotate(p)
        else:
            print "slide00000000000"
            self.paintStatic(p)
        
        self.preparePixmap(p)
    
class DigiFlip(QMainWindow):
    def __init__(self,parent = None):
        super(DigiFlip,self).__init__(parent)
        self.m_hour = Digits(self)
        self.m_hour.show()
        self.m_minute = Digits(self)
        self.m_minute.show()
        
        self.m_ticker = QBasicTimer()
        
        
        pal = QPalette(QColor(200,200,200))
        #pal = palette()
        pal.setColor(QPalette.Window, Qt.black);
        #Sets the color used for the given color role, in all color groups, to the specified solid color.

        #self.setPalette(pal)

        self.m_ticker.start(1000, self)
        #Send a timer event every second

        t = QTime.currentTime()
        self.m_hour.setNumber(t.hour())
        self.m_minute.setNumber(t.minute())
        self.updateTime()

        self.slideAction = QAction("&Slide", self)
        self.flipAction = QAction("&Flip", self)
        self.rotateAction = QAction("&Rotate", self)
        self.connect(self.slideAction, SIGNAL("triggered()"), self.chooseSlide)
        self.connect(self.flipAction, SIGNAL("triggered()"), self.chooseFlip)
        self.connect(self.rotateAction, SIGNAL("triggered()"), self.chooseRotate)
        #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE_WM)
        
        self.menuBar().addAction(self.slideAction);
        self.menuBar().addAction(self.flipAction);
        self.menuBar().addAction(self.rotateAction);
        #else
        self.addAction(self.slideAction)
        self.addAction(self.flipAction)
        self.addAction(self.rotateAction)
        self.setContextMenuPolicy(Qt.ActionsContextMenu);
        #Shows a context menu(right click)
        #endif

        #Real-time updates*/
    def updateTime(self):
        print "updatetime"
        t = QTime.currentTime()
        self.m_hour.flipTo(t.hour())
        self.m_minute.flipTo(t.minute())
        str = t.toString("hh:mm:ss")
        str.prepend(": ")
        if (self.m_hour.transition() == 0):
            str.prepend("Slide")
        if (self.m_hour.transition() == 1):
            str.prepend("Flip")
        if (self.m_hour.transition() == 2):
            str.prepend("Rotate")
        self.setWindowTitle(str)
    
    #Switch transition mode*/
    def switchTransition(self,delta):
        i = (self.m_hour.transition() + delta + 3) % 3
        self.m_hour.setTransition(i)
        self.m_minute.setTransition(i)
        self.updateTime()
    
    def resizeEvent(self,event):
        digitsWidth = self.width() / 2
        digitsHeight = digitsWidth * 1.2

        y = (self.height() - digitsHeight) / 3

        self.m_hour.resize(digitsWidth, digitsHeight)
        self.m_hour.move(0, y)

        self.m_minute.resize(digitsWidth, digitsHeight)
        self.m_minute.move(self.width() / 2, y)
    
    #Timer event,receive timer events */
    def timerEvent(self,event):
        self.updateTime()

    # Get key press event */
    def keyPressEvent(self,event):
        if (event.key() == Qt.Key_Right):
            self.switchTransition(1)
            event.accept()
        if (event.key() == Qt.Key_Left):
            self.switchTransition(-1)
            event.accept()
    
    
    def chooseSlide(self):
        self.m_hour.setTransition(0)
        self.m_minute.setTransition(0)
        self.updateTime()
    
    def chooseFlip(self):
        self.m_hour.setTransition(1)
        self.m_minute.setTransition(1)
        self.updateTime()
    
    def chooseRotate(self):
        self.m_hour.setTransition(2)
        self.m_minute.setTransition(2)
        self.updateTime()
    
    
    
    #include "digiflip.moc"

if __name__ == "__main__":

    app = QApplication(sys.argv)
    time = DigiFlip()
    time.resize(600, 400)
    time.show()

    app.exec_()
